﻿
Imports std

#Const prefix_match = True

Public Class variable
    Inherits iParseable

    Public Const templateTypeStart As Char = character.leftAngleBracket
    Public Const templateTypeEnd As Char = character.rightAngleBracket
    Public Const templateTypeSeparator As Char = character.comma
    Private Shared ReadOnly map_generate As map_generate_t = Nothing
    Private Shared ReadOnly set_generate As set_generate_t = Nothing
    Private Shared ReadOnly vector_generate As vector_generate_t = Nothing
    Private Shared ReadOnly list_generate As list_generate_t = Nothing
    Private Shared ReadOnly pointer_generate As pointer_generate_t = Nothing
    Private Shared ReadOnly indep_generate As indep_generate_t = Nothing

    Shared Sub New()
        map_generate = New map_generate_t()
        set_generate = New set_generate_t()
        vector_generate = New vector_generate_t()
        list_generate = New list_generate_t()
        pointer_generate = New pointer_generate_t()
        indep_generate = New indep_generate_t()
    End Sub

    Protected Friend Shared Function _isMeaningfulMark(ByVal c As Char) As Boolean
        Return isTemplateTypeStart(c) OrElse isTemplateTypeSeparator(c) OrElse isTemplateTypeEnd(c)
    End Function

    Private _type As typeDefination = Nothing
    Private _elementType1 As typeDefination = Nothing
    Private _elementType2 As typeDefination = Nothing

    Public Function type() As typeDefination
        Return _type
    End Function

    Public Function elementType1() As typeDefination
        Return _elementType1
    End Function

    Public Function elementType2() As typeDefination
        Return _elementType2
    End Function

    Friend Sub New(ByVal itype As typeDefination, _
                   ByVal ielementType1 As typeDefination, ByVal ielementType2 As typeDefination)
        'for bare_variable
        _type = itype
        _elementType1 = ielementType1
        _elementType2 = ielementType2
    End Sub

    Private Class map_generate_t
        Inherits md_t(Of Object)

        Protected Overrides Function cb(Of ET1 As IComparable(Of ET1), ET2) _
                                       (ByRef rtn As Object) As Boolean
            rtn = New elpmis_map(Of ET1, ET2)()
            Return True
        End Function
    End Class

    Private Class set_generate_t
        Inherits sd_t(Of Object)

        Protected Overrides Function cb(Of ET As IComparable(Of ET)) _
                                       (ByRef rtn As Object) As Boolean
            rtn = New elpmis_set(Of ET)()
            Return True
        End Function
    End Class

    Private Class vector_generate_t
        Inherits vd_t(Of Object)

        Protected Overrides Function cb(Of ET) _
                                       (ByRef rtn As Object) As Boolean
            rtn = New elpmis_vector(Of ET)()
            Return True
        End Function
    End Class

    Private Class list_generate_t
        Inherits ld_t(Of Object)

        Protected Overrides Function cb(Of ET) _
                                       (ByRef rtn As Object) As Boolean
            rtn = New elpmis_list(Of ET)()
            Return True
        End Function
    End Class

    Private Class pointer_generate_t
        Inherits pd_t(Of Object)

        Protected Overrides Function cb(Of ET) _
                                       (ByRef rtn As Object) As Boolean
            rtn = New elpmis_pointer(Of ET)()
            Return True
        End Function
    End Class

    Private Class indep_generate_t
        Inherits id_t(Of Object)

        Protected Overrides Function cb_b(ByRef rtn As Object) As Boolean
            rtn = New Boolean()
            Return True
        End Function

        Protected Overrides Function cb_d(ByRef rtn As Object) As Boolean
            rtn = New Double()
            Return True
        End Function

        Protected Overrides Function cb_i(ByRef rtn As Object) As Boolean
            rtn = New Int64()
            Return True
        End Function

        Protected Overrides Function cb_o(ByRef rtn As Object) As Boolean
            rtn = New Object()
            Return True
        End Function

        Protected Overrides Function cb_s(ByRef rtn As Object) As Boolean
            rtn = emptyString
            Return True
        End Function

        Protected Overrides Function cb_u(ByRef rtn As Object) As Boolean
            rtn = Nothing
            Return True
        End Function
    End Class

    'do we need to nest? as simple, do not support now
    Public Function invoke(ByRef output As Object) As Boolean
        Return typeInvoke(Nothing, type(), elementType1(), elementType2(), output, _
                          map_generate, vector_generate, set_generate, list_generate, pointer_generate, indep_generate)
    End Function

    Public Sub settype(ByVal t As typeDefination, _
                       Optional ByVal elementT1 As typeDefination = typeDefination.unknown, _
                       Optional ByVal elementT2 As typeDefination = typeDefination.unknown)
        _type = t
        _elementType1 = elementT1
        _elementType2 = elementT2
    End Sub

    Private Shared Function typecheck(ByVal c As Char) As Boolean
        Return language.english.isalpha(c)
    End Function

    Private Shared Function parseType(ByVal input As String, ByRef index As Int64, ByRef t As typeDefination, _
                                      ByVal start As Int64, ByVal [end] As Int64) As Boolean
        Dim s As String = Nothing
        If token(input, index, s, AddressOf typecheck, AddressOf typecheck) Then
            Dim i As Int64
            For i = start To [end] - 1
#If prefix_match Then
                If strsame(s, typeNaming(i), strlen(s), False) Then
#Else
                If strsame(s, typeNaming(i), False) Then
#End If
                    t = i
                    Return True
                End If
            Next

            t = typeDefination.unknown
            Return False
        Else
            Return False
        End If
    End Function

    Private Shared Function parseIndependentType(ByVal s As String, ByRef _index As Int64, _
                                                 ByRef t As typeDefination) As Boolean
        Dim index As Int64
        index = _index
        If parseType(s, index, t, 0, typeDefination.INDEPENDENT_TYPES) Then
            _index = index
            Return True
        Else
            Return False
        End If
    End Function

    Private Shared Function parseTemplateTypeImpl(ByVal s As String, ByRef index As Int64, _
                                                  ByRef t As typeDefination) As Boolean
        Return parseType(s, index, t, typeDefination.INDEPENDENT_TYPES + 1, typeDefination.TEMPLATE_TYPES)
    End Function

    Private Shared Function isTemplateTypeStart(ByVal c As Char) As Boolean
        Return c = templateTypeStart
    End Function

    Private Shared Function isTemplateTypeSeparator(ByVal c As Char) As Boolean
        Return c = templateTypeSeparator
    End Function

    Private Shared Function isTemplateTypeEnd(ByVal c As Char) As Boolean
        Return c = templateTypeEnd
    End Function

    Private Shared Function parseTemplateType(ByVal input As String, ByRef _index As Int64, _
                                              ByRef t As typeDefination, _
                                              ByRef elementT As typeDefination, _
                                              ByRef elementT2 As typeDefination) As Boolean
        Dim index As Int64
        index = _index
        If parseTemplateTypeImpl(input, index, t) Then
            If token(input, index, Nothing, AddressOf isTemplateTypeStart, AddressOf [false]) Then
                If parseIndependentType(input, index, elementT) AndAlso _
                   ((t <> typeDefination.set AndAlso t <> typeDefination.map) OrElse _
                    elementT <> typeDefination.var) Then
                    'set & map do not support to use var
                    'map need two element types
                    If t = typeDefination.map Then
                        If token(input, index, Nothing, AddressOf isTemplateTypeSeparator, AddressOf [false]) Then
                            If parseIndependentType(input, index, elementT2) Then
                                If token(input, index, Nothing, AddressOf isTemplateTypeEnd, AddressOf [false]) Then
                                    _index = index
                                    Return True
                                Else
                                    Return False
                                End If
                            Else
                                logparseerror("cannot parse second independent type, ", index)
                                Return False
                            End If
                        Else
                            Return False
                        End If
                    Else
                        If token(input, index, Nothing, AddressOf isTemplateTypeEnd, AddressOf [false]) Then
                            _index = index
                            Return True
                        Else
                            Return False
                        End If
                    End If
                Else
                    logparseerror("cannot parse first independent type, " + _
                                  "or independent type does not match template type requirement.", index)
                    Return False
                End If
            Else
                Return False
            End If
        Else
            logparseerror("cannot parse template type", index)
            Return False
        End If
    End Function

    Protected Shared Function parseImpl(ByVal input As String, ByRef index As Int64, _
                                        ByRef output As variable) As Boolean
        Dim t As typeDefination = typeDefination.unknown
        Dim elementT1 As typeDefination = typeDefination.unknown
        Dim elementT2 As typeDefination = typeDefination.unknown

        If parseIndependentType(input, index, t) OrElse _
           parseTemplateType(input, index, t, elementT1, elementT2) Then
            output = New variable(t, elementT1, elementT2)
            Return True
        Else
            Return False
        End If
    End Function

    Public Shared Function parse(ByVal input As String, ByRef index As Int64, ByRef output As variable) As Boolean
        Return parsebase(input, index, output, AddressOf parseImpl)
    End Function

    Public Overrides Function ToString() As String
        Return typeNaming(type()) + "<" + typeNaming(elementType1()) + "," + typeNaming(elementType2()) + ">"
    End Function

    'type helper functions, do not interest on region
    Public Function isTemplateType() As Boolean
        Return _types.isTemplateType(type())
    End Function

    Public Function isStdType() As Boolean
        Return _types.isStdType(type())
    End Function

    Public Function isPointer() As Boolean
        Return _types.isPointer(type())
    End Function

    Public Function isIndependentType() As Boolean
        Return _types.isIndependentType(type())
    End Function

    Public Function isUnknownType() As Boolean
        Return _types.isUnknownType(type())
    End Function

    Public Function isType(ByVal t As typeDefination, Optional ByVal enableVar As Boolean = False) As Boolean
        Return _types.typeEqual(type(), t) OrElse (enableVar AndAlso _types.typeEqual(type(), typeDefination.var))
    End Function

    Private Shared Function matchtype(ByVal this_t As typeDefination, ByVal match_t As typeDefination, _
                                      ByVal enableVar As Boolean) As Boolean
        Return _types.typeEqual(this_t, match_t) OrElse (enableVar AndAlso _types.typeEqual(this_t, typeDefination.var))
    End Function

    Private Function isElementType1(ByVal et1 As typeDefination, Optional ByVal enableVar As Boolean = True) As Boolean
        Return matchtype(elementType1(), et1, enableVar)
    End Function

    Private Function isElementType2(ByVal et2 As typeDefination, Optional ByVal enableVar As Boolean = True) As Boolean
        Return matchtype(elementType2(), et2, enableVar)
    End Function

    Public Function isPointerOf(ByVal et1 As typeDefination, Optional ByVal enableVar As Boolean = True) As Boolean
        Return isPointer() AndAlso isElementType1(et1, enableVar)
    End Function

    Public Function isPointerOfString(Optional ByVal enableVar As Boolean = True) As Boolean
        Return isPointerOf(typeDefination.string, enableVar)
    End Function

    Public Function isPointerOfVar() As Boolean
        Return isPointerOf(typeDefination.var, False)
    End Function
End Class
